[小ネタ] Python(Boto 3)で5GB以上のS3オブジェクトをコピーするときはcopyメソッドを使おう
はじめに
清水です。タイトル通りなのですが、Python(Boto 3)で5GBを超える容量のS3オブジェクトをコピーする場合には、copy_objectメソッドではなくcopyメソッドを使いましょう。copy_objectメソッドでは5GB以上のS3オブジェクトをコピーしようとしてもエラーとなってしまいます。当初このことを知らずにハマってしまったので、備忘録がてらまとめてみたいと思います。
copy_objectメソッドを使ったS3オブジェクトコピーのコード
まずはPython(Boto3)でS3上のオブジェクトをコピーするのに典型的な、copy_objectメソッドを使ったコードを確認しておきましょう。AWS公式のSDKコードサンプルからの引用です。
import logging import boto3 from botocore.exceptions import ClientError def copy_object(src_bucket_name, src_object_name, dest_bucket_name, dest_object_name=None): """Copy an Amazon S3 bucket object :param src_bucket_name: string :param src_object_name: string :param dest_bucket_name: string. Must already exist. :param dest_object_name: string. If dest bucket/object exists, it is overwritten. Default: src_object_name :return: True if object was copied, otherwise False """ # Construct source bucket/object parameter copy_source = {'Bucket': src_bucket_name, 'Key': src_object_name} if dest_object_name is None: dest_object_name = src_object_name # Copy the object s3 = boto3.client('s3') try: s3.copy_object(CopySource=copy_source, Bucket=dest_bucket_name, Key=dest_object_name) except ClientError as e: logging.error(e) return False return True def main(): """Exercise copy_object()""" # Assign these values before running the program src_bucket_name = 'SRC_BUCKET_NAME' src_object_name = 'SRC_OBJECT_NAME' dest_bucket_name = 'DEST_BUCKET_NAME' dest_object_name = 'DEST_OBJECT_NAME' # Set up logging logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(asctime)s: %(message)s') # Copy the object success = copy_object(src_bucket_name, src_object_name, dest_bucket_name, dest_object_name) if success: logging.info(f'Copied {src_bucket_name}/{src_object_name} to ' f'{dest_bucket_name}/{dest_object_name}') if __name__ == '__main__': main()
容量の大きくないファイルであればこちらのコードで問題なく動作します。
INFO: 2020-02-29 08:36:52,952: Copied my-s3-bucket-1/s3-copy-object-test/100M.dummy to my-s3-bucket-2/s3-copy-object-test/100M.dummy
しかし容量の大きな、例えば10GBのファイルの場合は以下のようにエラーとなっていしまいます。(後述しますが上限は5GBです)
ERROR: 2020-02-29 08:38:38,402: An error occurred (InvalidRequest) when calling the CopyObject operation: The specified copy source is larger than the maximum allowable size for a copy source: 5368709120
copyメソッドを使ったS3オブジェクトコピーのコード
容量の大きなオブジェクト(5GB以上)のコピーに利用できるのがcopyメソッドです。先ほどのcopy_objectメソッドを使ったサンプルの、copy_object関数部分を変更するかたちで使い方を確認してみると以下のようになります。
def copy_object(src_bucket_name, src_object_name, dest_bucket_name, dest_object_name=None): """Copy an Amazon S3 bucket object :param src_bucket_name: string :param src_object_name: string :param dest_bucket_name: string. Must already exist. :param dest_object_name: string. If dest bucket/object exists, it is overwritten. Default: src_object_name :return: True if object was copied, otherwise False """ # Construct source bucket/object parameter copy_source = {'Bucket': src_bucket_name, 'Key': src_object_name} if dest_object_name is None: dest_object_name = src_object_name # Copy the object s3 = boto3.resource('s3') try: s3.meta.client.copy(copy_source, dest_bucket_name, dest_object_name) except ClientError as e: logging.error(e) return False return True
変更箇所がハイライトされていますが、boto3.client('s3')
の代わりにboto3.resource('s3')
、s3.copy_object()
の代わりにs3.meta.client.copy()
を使う、という具合です。
こちらで例えば10GBのオブジェクトコピーでも問題なく行えます。
INFO: 2020-02-29 08:50:56,931: Copied my-s3-bucket-1/s3-copy-object-test/10G.dummy to my-s3-bucket-2/s3-copy-object-test/10G.dummy
copy_objectメソッドとcopyメソッドの違いを確認
copyメソッドについては、必要に応じてマルチパートコピー、マルチプルスレッドを利用するマネージドな転送方法とのことです。S3についてはオブジェクトの最大サイズは5TBですが、1回のPUT処理でアップロードできるオブジェクトサイズは5GBという制限があります。copyメソッドではコピー対象のオブジェクトサイズが5GBを超える場合は自動でマルチパートアップロードを用いて実現しているようです。
また、それならcopy_objectメソッド自体も、copyオブジェクトのように自動でマルチパートアップロード対応など行われるようになるのか、という点については、copy_objectがraw API methodであるから今後も行われないようです。
- S3.Client.copy / S3 — Boto 3 Docs 1.12.10 documentation
- S3.Client.copy_object / S3 — Boto 3 Docs 1.12.10 documentation
- s3 client copy_object 5GB limit, while s3 resource copy works · Issue #1715 · boto/boto3 · GitHub
まとめ
Python(Boto 3)で5GB以上S3オブジェクトをコピーするときはcopyメソッドを使いましょう。またS3においては、オブジェクトのサイズで5GBはマルチパートアップロードが必須になるか否かの上限となります。他のSDKなどでもS3オブジェクトコピーやアップロードする際には、5G以上に対応しているか(そもそも対応する必要があるかも)、確認しておきましょう。